package pers.jzh.std.scala.chapter6

/**
 * 有理数：可以用分数n/d表示，其中n和d是整数，但d不能是零
 * n：类参数，分子
 * d：类参数，分母
 */
class Rational(n:Int, d:Int) {

  /*
  辅助构造方法：def this()
  scala中，辅助构造方法的第一句必须调用同一个类中的另一个构造方法，即this(...)
   */
  def this(n: Int) = this(n, 1)

  /*
  "前提条件"是用来对传入方法、构造方法的值的约束，一旦返回false，则会抛出异常阻止对象的构建
   */
  require(d != 0)

  private val g = gcd(n.abs, d.abs)

  /*
  如果想基于rational.n的方式访问分子分母，那么需要将他们定义成字段
   */
  val numer: Int = n / g

  val denom: Int = d / g



  /*
  tips：scala编译器会将类定义体中的非字段、非方法定义的代码编译进类的主构造方法中。
   */
//  println(s"create a Rational($n/$d)")

  override def toString: String = if(denom == 1) s"$numer" else s"$numer/$denom"

  def +(that: Rational): Rational = {
    if(null == that) throw new IllegalArgumentException("param {that} can not be null!")
    val a = numer * that.denom + denom * that.numer
    val b = denom * that.denom
    new Rational(a, b)
  }

  def +(that: Int): Rational = {
    if(null == that) throw new IllegalArgumentException("param {that} can not be null!")
    new Rational(numer + that * denom, denom * that)
  }

  def -(that: Rational): Rational = {
    if(null == that) throw new IllegalArgumentException("param {that} can not be null!")
    new Rational(numer * that.denom - denom * that.numer, denom * that.denom)
  }

  def -(that: Int): Rational = {
    if(null == that) throw new IllegalArgumentException("param {that} can not be null!")
    new Rational(numer - that*denom, denom)
  }

  def *(that: Rational): Rational = {
    if(null == that) throw new IllegalArgumentException("param {that} can not be null!")
    val a = numer * that.numer
    val b = denom * that.denom
    new Rational(a, b)
  }

  def *(that: Int) : Rational = {
    if(null == that) throw new IllegalArgumentException("param {that} can not be null!")
    new Rational(numer * that, denom)
  }

  def /(that: Rational): Rational = {
    if(null == that) throw new IllegalArgumentException("param {that} can not be null!")
    new Rational(numer * that.denom, denom * that.numer)
  }

  def /(that: Int): Rational = {
    if(null == that) throw new IllegalArgumentException("param {that} can not be null!")
    new Rational(numer, denom * that)
  }

  /**
   * 获取最大公约数
   * @param a
   * @param b
   * @return 参数$a和参数$b的最大公约数
   */
  private def gcd(a:Int, b:Int): Int = {
    if(b == 0) a else gcd(b, a % b)
  }



}
